package com.by.basicgateway.config;

import com.by.toolkit.consts.WebGlobalConst;
import com.by.toolkit.enums.FlagEnum;
import com.by.toolkit.utils.RequestIdUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Slf4j
@Data
@Component
public class ByServerWebExchangeMatcher implements ServerWebExchangeMatcher {

    private static final ServerWebExchangeMatcher OPTIONS_MATCHER = ServerWebExchangeMatchers.pathMatchers(HttpMethod.OPTIONS, "/**");

    private ServerWebExchangeMatcher matcher;

    @Override
    public Mono<MatchResult> matches(ServerWebExchange exchange) {
        return this.matcher
                .matches(exchange)
                .flatMap(this::negate)
                .doOnNext(matchResult -> {
                    ServerHttpRequest request = exchange.getRequest();
                    String path = request.getURI().getPath();
                    boolean match = matchResult.isMatch();
                    log.info("[ByServerWebExchangeMatcher][matches] path:[{}] matches:[{}]", path, match);
                    // 请求id
                    request.mutate()
                            .header(WebGlobalConst.REQUEST_ID, RequestIdUtil.requestStart(request.getHeaders().getFirst(WebGlobalConst.REQUEST_ID)))
                            .header(WebGlobalConst.FROM_GATEWAY, FlagEnum.YES_STR)
                            .header(WebGlobalConst.UN_AUTH, FlagEnum.resolve(!match).toString())
                            .build();
                });
    }

    private Mono<MatchResult> negate(MatchResult matchResult) {
        return matchResult.isMatch() ? MatchResult.notMatch() : MatchResult.match();
    }

    public void refreshMatch(List<String> filterPaths) {
        if (CollectionUtils.isEmpty(filterPaths)) {
            return;
        }
        log.info("[ByServerWebExchangeMatcher][refreshMatch] filterPaths:[{}]", filterPaths);
        ServerWebExchangeMatcher serverWebExchangeMatcher = ServerWebExchangeMatchers.pathMatchers(filterPaths.toArray(String[]::new));
        matcher = ServerWebExchangeMatchers.matchers(OPTIONS_MATCHER, serverWebExchangeMatcher);
    }
}
